package com.lyj.mall.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.google.gson.Gson;
import com.lyj.mall.enums.ProductStatusEnum;
import com.lyj.mall.enums.ResponseEnum;
import com.lyj.mall.form.Cart;
import com.lyj.mall.form.CartAddForm;
import com.lyj.mall.form.CartUpdateForm;
import com.lyj.mall.pojo.Product;
import com.lyj.mall.service.CartService;
import com.lyj.mall.service.ProductService;
import com.lyj.mall.vo.CartProductVo;
import com.lyj.mall.vo.CartVo;
import com.lyj.mall.vo.ResponseVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static com.lyj.mall.enums.ResponseEnum.CART_PRODUCT_NOT_FIND;

/**
 * @author lyj
 * @date 2020/1/17 15:27
 */
@Service
public class CartServiceImpl implements CartService {

    private static final String CART_REDIS_KEY = "cart_%d";

    @Autowired
    private ProductService productService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    private Gson gson = new Gson();

    @Override
    public ResponseVo<CartVo> add(Integer uid, CartAddForm cartAddForm) {
        Integer quantity = 1;
        // 1、商品是否存在
        Product product = productService.getById(cartAddForm.getProductId());
        if (null == product) {
            return ResponseVo.error(ResponseEnum.PRODUCT_NOT_FIND);
        }
        // 2、商品是否在售
        if (!product.getStatus().equals(ProductStatusEnum.ON_SELE.getStatus())) {
            return ResponseVo.error(ResponseEnum.PRODUCT_OFF_SALE_OR_DELETED);
        }
        // 3、库存是否充足
        if (product.getStock() <= 0) {
            return ResponseVo.error(ResponseEnum.PRODUCT_STOCK_NOT_ENOUGH);
        }
        Cart cart = null;
        // 4、查询redis中否有该购物车
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String value = opsForHash.get(String.format(CART_REDIS_KEY, uid), String.valueOf(product.getId()));
        if (StrUtil.isEmpty(value)) {
            // 没有该商品则加入
            cart = new Cart(cartAddForm.getProductId(), quantity, cartAddForm.getSelected());
        } else {
            // 有该商品则数量 +1
            cart = gson.fromJson(value, Cart.class);
            cart.setQuantity(cart.getQuantity() + quantity);
        }
        opsForHash.put(String.format(CART_REDIS_KEY, uid),
                String.valueOf(product.getId()),
                gson.toJson(cart));
        return list(uid);
    }

    @Override
    public ResponseVo<CartVo> list(Integer uid) {
        CartVo cartVo = new CartVo();

        String redisKey = String.format(CART_REDIS_KEY, uid);
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();

        Boolean selectedAll = true;
        BigDecimal cartTotalPrice = BigDecimal.ZERO;
        Integer cartTotalQuantity = 0;

        Map<String, String> entries = opsForHash.entries(redisKey);

        List<CartProductVo> cartProductVoList = CollectionUtil.newArrayList();

        for (String e : entries.keySet()) {
            Integer key = Integer.valueOf(e);
            Cart cart = gson.fromJson(entries.get(e), Cart.class);
            Product product = productService.getById(key);
            if (BeanUtil.isNotEmpty(product)) {
                CartProductVo cartProductVo = new CartProductVo();
                cartProductVo.setProductId(key);
                cartProductVo.setProductMainImage(product.getMainImage());
                cartProductVo.setProductName(product.getName());
                cartProductVo.setProductPrice(product.getPrice());
                cartProductVo.setProductSelected(cart.getSelected());
                cartProductVo.setProductStatus(product.getStatus());
                cartProductVo.setProductStock(product.getStock());
                cartProductVo.setProductSubtitle(product.getSubtitle());
                cartProductVo.setProductTotalPrice(product.getPrice().multiply(BigDecimal.valueOf(cart.getQuantity())));
                cartProductVo.setQuantity(cart.getQuantity());
                cartProductVoList.add(cartProductVo);

                if (!cartProductVo.getProductSelected()) {
                    selectedAll = false;
                } else if (cartProductVo.getProductSelected()) {
                    cartTotalPrice = cartTotalPrice.add(cartProductVo.getProductTotalPrice());
                }

                cartTotalQuantity += cartProductVo.getQuantity();
            }
        }
        cartVo.setCartProductVoList(cartProductVoList);
        cartVo.setCartTotalPrice(cartTotalPrice);
        cartVo.setCartTotalQuantity(cartTotalQuantity);
        cartVo.setSelectedAll(selectedAll);
        return ResponseVo.success(cartVo);
    }

    @Override
    public ResponseVo<CartVo> update(Integer uid, Integer productId, CartUpdateForm cartUpdateForm) {
        String redisKey = String.format(CART_REDIS_KEY, uid);
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();

        String value = opsForHash.get(redisKey, String.valueOf(productId));
        Cart cart = gson.fromJson(value, Cart.class);
        if (StrUtil.isEmpty(value)) {
            return ResponseVo.error(CART_PRODUCT_NOT_FIND);
        }
        if (null != cartUpdateForm.getQuantity() && cartUpdateForm.getQuantity() >= 0) {
            cart.setQuantity(cartUpdateForm.getQuantity());
        }
        if (null != cartUpdateForm.getSelected()) {
            cart.setSelected(cartUpdateForm.getSelected());
        }
        opsForHash.put(redisKey, String.valueOf(productId), gson.toJson(cart));

        return list(uid);
    }

    @Override
    public ResponseVo<CartVo> delete(Integer uid, Integer productId) {
        String redisKey = String.format(CART_REDIS_KEY, uid);
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();

        String value = opsForHash.get(redisKey, String.valueOf(productId));
        if (StrUtil.isEmpty(value)) {
            return ResponseVo.error(CART_PRODUCT_NOT_FIND);
        }

        opsForHash.delete(redisKey, String.valueOf(productId));

        return list(uid);
    }

    @Override
    public ResponseVo<CartVo> selectAll(Integer uid) {
        String redisKey = String.format(CART_REDIS_KEY, uid);
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();

        Map<String, String> entries = opsForHash.entries(redisKey);

        entries.entrySet().forEach(e -> {
            String value = e.getValue();
            Cart cart = gson.fromJson(value, Cart.class);
            cart.setSelected(true);
            opsForHash.put(redisKey, String.valueOf(cart.getProductId()), gson.toJson(cart));
        });

        return list(uid);
    }

    @Override
    public ResponseVo<CartVo> unSelectAll(Integer uid) {
        String redisKey = String.format(CART_REDIS_KEY, uid);
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();

        Map<String, String> entries = opsForHash.entries(redisKey);
        entries.entrySet().forEach(e -> {
            String value = e.getValue();
            Cart cart = gson.fromJson(value, Cart.class);
            cart.setSelected(false);
            opsForHash.put(redisKey, String.valueOf(cart.getProductId()), gson.toJson(cart));
        });

        return list(uid);
    }

    @Override
    public ResponseVo<Integer> sum(Integer uid) {
        String redisKey = String.format(CART_REDIS_KEY, uid);
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        Map<String, String> entries = opsForHash.entries(redisKey);
        Integer total = 0;
        for (Map.Entry<String, String> e : entries.entrySet()) {
            Cart cart = gson.fromJson(e.getValue(), Cart.class);
            total += cart.getQuantity();
        }
        return ResponseVo.success(total);
    }

    @Override
    public List<Cart> listForCart(Integer uid) {
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String redisKey  = String.format(CART_REDIS_KEY, uid);
        Map<String, String> entries = opsForHash.entries(redisKey);

        List<Cart> cartList = new ArrayList<>();
        for (Map.Entry<String, String> entry : entries.entrySet()) {
            cartList.add(gson.fromJson(entry.getValue(), Cart.class));
        }
        return cartList;
    }

}
